package net.sunofbeach.blog.controller.user;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import net.sunofbeach.blog.pojo.User;
import net.sunofbeach.blog.pojo.query.UserQuery;
import net.sunofbeach.blog.pojo.vo.UserVO;
import net.sunofbeach.blog.response.Result;
import net.sunofbeach.blog.service.UserService;
import net.sunofbeach.blog.utils.TextUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author bing_  @create 2021/11/24-18:01
 */
@Slf4j
@Api(tags = "用户管理")
@RestController
@RequestMapping("/user")
public class UserApi {

    @Resource
    private UserService userService;


    /**
     * 初始化管理员账户
     *
     * @param user
     * @param request
     * @return
     */
    @ApiOperation("初始化管理员账户")
    @PostMapping("/admin_account")
    public Result initManagerAccount(@RequestBody User user, HttpServletRequest request) {
        log.info("username == > " + user.getUsername());
        log.info("password == > " + user.getPassword());
        log.info("email == > " + user.getEmail());
        return userService.initManagerAccount(user, request);
    }


    /**
     * 用户注册
     *
     * @param user        用户
     * @param emailCode   邮箱验证码
     * @param captchaCode 图灵验证码
     * @param captchaKey  图灵验证码key
     * @param request     用于传IP地址
     * @return
     */
    @ApiOperation("用户注册")
    @PostMapping("/register")
    public Result register(@RequestBody User user,
                           @RequestParam("emailCode") String emailCode,
                           @RequestParam("captchaCode") String captchaCode,
                           @RequestParam("captchaKey") String captchaKey,
                           HttpServletRequest request) {
        // emailCode 邮箱验证码，captchaCode 图灵验证码
        return userService.register(user, emailCode, captchaCode, captchaKey, request);
    }


    /**
     * 用户登录
     *
     * @param captcha    图灵验证码
     * @param captchaKey 图灵key
     * @param user       用户
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("登录")
    @PostMapping("/login/{captcha}/{captchaKey}")
    public Result login(@PathVariable("captcha") String captcha,
                        @PathVariable("captchaKey") String captchaKey,
                        @RequestBody User user,
                        HttpServletRequest request,
                        HttpServletResponse response) {
        return userService.doLogin(captcha, captchaKey, user, request, response);
    }


    /**
     * 获取图灵验证码
     * 存入 redis，有效时长 10 分钟
     * postMan GET http://localhost:2021/user/captcha?captcha_key=3815825449258
     */
    @ApiOperation("获取图灵验证码")
    @GetMapping("/captcha")
    public void getCaptcha(HttpServletResponse response,
                           @RequestParam("captcha_key") String captchaKey) {
        try {
            userService.createCaptcha(response, captchaKey);
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    /**
     * 发送邮件验证码
     * <p>
     * 使用场景： 注册、找回密码、修改邮箱（会输入新的密码）
     * 注册： 如果已经注册，提示 该邮箱已经注册；
     * 找回密码： 如果没有注册，提示 该邮箱未注册
     * 修改邮箱（新的邮箱）： 如果已经注册，提示 该邮箱已经被注册
     * 解决： 根据不类型的场景，执行对应的业务逻辑。
     *
     * @param request      校验IP
     * @param type         不同类型使用场景：注册 register、找回密码 forget、修改邮箱 update
     * @param emailAddress 邮箱地址
     * @return
     */
    @ApiOperation("发送验证码邮件")
    @GetMapping("/verifyCode")
    public Result sendVerifyCode(HttpServletRequest request, @RequestParam("type") String type, @RequestParam("emailAddress") String emailAddress) {
        log.info("email ==> " + emailAddress);
        // request 为了获取用户的 IP 地址,防止同一 IP 轰炸
        return userService.sendEmail(request, type, emailAddress);
    }


    /**
     * 获取作者信息
     *
     * @param userId
     * @return
     */
    @ApiOperation("获取作者信息")
    @GetMapping("/{userId}")
    public Result getUserInfo(@PathVariable("userId") String userId) {
        if (TextUtils.isEmpty(userId)) {
            return Result.fail().message("用户不存在");
        }
        return userService.getUserInfo(userId);
    }


    /**
     * 检查邮箱是否被注册
     * 返回给前端
     *
     * @param email
     * @return
     */
    @ApiOperation("检查邮箱是否被注册/返回给前端")
    @ApiResponses({
            @ApiResponse(code = 20000, message = "表示邮箱已经注册"),
            @ApiResponse(code = 40000, message = "表示当前邮箱未注册")
    })
    @GetMapping("/email")
    public Result checkEmailToFront(@RequestParam("email") String email) {
        return userService.checkEmailToFront(email);
    }

    /**
     * 检查用户名是否被注册
     * 返回给前端
     *
     * @param username
     * @return
     */
    @ApiOperation("检查用户名是否被注册/返回给前端")
    @ApiResponses({
            @ApiResponse(code = 20000, message = "表示用户名已经注册"),
            @ApiResponse(code = 40000, message = "表示当前用户名未注册")
    })
    @GetMapping("/username")
    public Result checkUsernameToFront(@RequestParam("username") String username) {
        return userService.checkUsernameToFront(username);
    }


    /**
     * 更新用户信息 user-info
     * 允许用户修改的内容：
     * 1、头像
     * 2、用户名（唯一的）
     * 3、签名
     * 4、密码（单独修改）
     * 5、Email (唯一的，单独修改）
     *
     * @return
     */
    @ApiOperation("用户更新信息")
    @PutMapping("/userInfo")
    public Result updateUserInfo(HttpServletRequest request, @RequestBody User user) {
        // 需要检查是否是当前登录用户
        return userService.updateUserInfo(request, user);
    }


    /**
     * 逻辑删除用户
     * 需要管理员权限
     *
     * @param userId
     * @return
     * @PreAuthorize("@permission.admin()") 需要管理员权限才可访问此接口, 这里使用此注解无效
     */
    @ApiOperation("删除用户")
    @DeleteMapping("/{userId}")
    public Result deleteUser(@PathVariable("userId") String userId) {
        if (TextUtils.isEmpty(userId)) {
            return Result.fail().message("用户ID不能为空");
        }
        // 判断当前操作的用户身份
        // 根据用户角色判断是否可以删除
        // TODO: 通过注解的方式来控制权限
        return userService.deleteUserById(userId);
    }


    /**
     * 修改密码 password
     * 一、普通修改密码（登录后修改密码）： 通过旧密码对比来更新密码
     * 二、找回密码，也可以修改密码，未登录时操作
     * 发送验证码到邮箱 / 手机  一一> 判官验证码是否正确 （ 对应的邮箱 / 手机号所注册的账号是否属于你）
     * <p>
     * 步骤：
     * 1、用户填写邮箱
     * 2、用户获取验证码  type = forget
     * 3、填写验证码
     * 4、填写新的密码
     * 5、提交数据
     * <p>
     * 数据包括：
     * 1、邮箱和新密码
     * 2、验证码
     * 如果验证码正确 一一> 所用邮箱注册的账号就是你的，可以修改密码
     * <p>
     * 测试：
     * 获取邮箱验证码  GET  localhost:2021/user/verifyCode?type=forget&emailAddress=bing_yu2001@qq.com
     * 修改密码：
     *
     * @param user 放两个数据：邮箱、密码
     * @return
     */
    @ApiOperation("用户找回密码")
    @PutMapping("/password/{verifyCode}")
    public Result updatePassword(@PathVariable("verifyCode") String verifyCode, @RequestBody User user) {
        return userService.updateUserPassword(verifyCode, user);
    }


    /**
     * 更用户新邮箱
     * <p>
     * 思路：
     * 1、用户必须已经登录
     * 2、新的邮箱没有注册过
     * <p>
     * 用户的步骤：
     * 1、已经登录
     * 2、输入新的邮箱地址
     * 3、获取邮箱验证码  type=update
     * 4、输入邮箱验证码
     * 5、提交数据
     * <p>
     * 需要提交的数据
     * 1、新的邮箱地址
     * 2、邮箱验证码
     * 3、其它信息我们可以从 token 里获取
     *
     * @param email
     * @param verifyCode
     * @return
     */
    @ApiOperation("用户修改邮箱")
    @PutMapping("/email")
    public Result updateEmail(@RequestParam("email") String email, @RequestParam("verifyCody") String verifyCode) {
        if (TextUtils.isEmpty(email)) {
            return Result.fail().message("邮箱不能为空");
        }
        return userService.updateEmail(email, verifyCode);
    }


    /**
     * 退出登录
     * 1、拿到 token_key
     * 2、删除redis里对应的token
     * 3、删除mysql里对应的 refreshToken
     * 4、删除cookie里的token_key
     *
     * @return
     */
    @ApiOperation("退出")
    @GetMapping("/logout")
    public Result logout() {
        return userService.doLogout();
    }


    /**
     * 后台-条件分页获取用户列表
     * 需要管理员权限
     *
     * @param page
     * @param size
     * @return @PreAuthorize("@permission.admin()") 权限注解
     */
    @ApiOperation("后台-分页获取用户列表")
    @PreAuthorize("@permission.admin()")
    @GetMapping("/list/{page}/{size}")
    public Result search(@ApiParam(value = "当前页码", required = true) @PathVariable Long page,
                         @ApiParam(value = "每页记录数", required = true) @PathVariable Long size,
                         @ApiParam("用户列表查询对象") UserQuery query) {
        Page<UserVO> pageParam = new Page<>(page, size);
        IPage<UserVO> pageModel = userService.selectPage(pageParam, query);
        return Result.ok(pageModel);
    }


    @ApiOperation("通过Token获取用户信息")
    @GetMapping("/check/token")
    public Result parseToken() {
        return userService.parseToken();
    }


    @ApiOperation("管理员重置用户密码")
    @PutMapping("/reset/password/{userId}")
    public Result resetPassword(@PathVariable("userId") String userId, @RequestParam("password") String password) {
        if (StringUtils.isEmpty(userId)) {
            return Result.fail().message("用户ID不能为空");
        }
        if (StringUtils.isEmpty(password)) {
            return Result.fail().message("密码不能为空");
        }
        return userService.resetPassword(userId, password);
    }

}




